package com.itjin.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itjin.mapper.CourseMapper;
import com.itjin.model.domain.dto.CourseCreateDTO;
import com.itjin.model.domain.dto.CourseEditDTO;
import com.itjin.model.domain.entity.Course;
import com.itjin.model.domain.vo.CourseDetailVO;
import com.itjin.service.CourseScheduleService;
import org.springframework.beans.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import ai.z.openapi.ZhipuAiClient;
import ai.z.openapi.service.model.*;
import ai.z.openapi.core.Constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 课程表服务实现类
 */
@Slf4j
@Service
public class CourseScheduleServiceImpl implements CourseScheduleService {

    @Value("${zhipu.ai.api-key}")
    private String zhipuApiKey;
    
    @Autowired
    private CourseMapper courseMapper;
    
    private ZhipuAiClient zhipuClient;
    
    /**
     * 初始化智谱AI客户端
     */
    private ZhipuAiClient getZhipuClient() {
        if (zhipuClient == null) {
            zhipuClient = ZhipuAiClient.builder()
                    .apiKey(zhipuApiKey)
                    .build();
        }
        return zhipuClient;
    }

    @Override
    public List<Course> parseScheduleFromImage(Integer userId, String imageUrl) {
        try {
            log.info("开始解析用户{}的课程表图片: {}", userId, imageUrl);
            
            // 构建提示词
            String prompt = buildOCRPrompt();
            
            // 调用GLM-4V进行OCR识别
            String aiResponse = callGLMForOCR(prompt, imageUrl);
            log.info("GLM-4V识别结果: {}", aiResponse);
            
            // 解析AI返回的JSON格式课程信息
            List<Course> courses = parseCoursesFromAIResponse(userId, aiResponse);
            
            log.info("成功解析出{}门课程", courses.size());
            return courses;
            
        } catch (Exception e) {
            log.error("解析课程表图片失败: ", e);
            throw new RuntimeException("课程表解析失败: " + e.getMessage());
        }
    }

    @Override
    public Object getUserWeeklySchedule(Integer userId, Integer week) {
        try {
            log.info("获取用户{}第{}周的课程表", userId, week);
            
            // 查询用户的课程
            QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", userId)
                       .eq("isDelete", 0)
                       .le("weekStart", week)
                       .ge("weekEnd", week);
            
            List<Course> courses = courseMapper.selectList(queryWrapper);
            
            // 按星期分组
            Map<String, List<Map<String, Object>>> weeklySchedule = new LinkedHashMap<>();
            String[] weekdays = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
            
            // 初始化每天的课程列表
            for (String day : weekdays) {
                weeklySchedule.put(day, new ArrayList<>());
            }
            
            // 解析每门课程的时间安排
            for (Course course : courses) {
                parseAndAddCourseToSchedule(course, weeklySchedule);
            }
            
            return weeklySchedule;
            
        } catch (Exception e) {
            log.error("获取用户课程表失败: ", e);
            throw new RuntimeException("获取课程表失败: " + e.getMessage());
        }
    }

    @Override
    public int saveCourses(List<Course> courses) {
        try {
            int savedCount = 0;
            for (Course course : courses) {
                course.setCreateTime(LocalDateTime.now());
                course.setUpdateTime(LocalDateTime.now());
                course.setIsDelete(0);
                
                int result = courseMapper.insert(course);
                if (result > 0) {
                    savedCount++;
                }
            }
            log.info("成功保存{}门课程", savedCount);
            return savedCount;
            
        } catch (Exception e) {
            log.error("保存课程信息失败: ", e);
            throw new RuntimeException("保存课程失败: " + e.getMessage());
        }
    }

    /**
     * 构建OCR识别提示词
     */
    private String buildOCRPrompt() {
        return """
            请分析这张课程表图片，提取所有课程信息。
            
            请严格按照以下JSON格式返回结果：
            
            {
                "courses": [
                    {
                        "courseName": "课程名称",
                        "teacherName": "",
                        "credit": 2,
                        "courseType": 0,
                        "classroom": "教室号",
                        "weekStart": 1,
                        "weekEnd": 20,
                        "classTime": "Monday:08:00-09:40",
                        "courseDescription": ""
                    }
                ]
            }
            
            注意：
            - classTime格式：星期:开始时间-结束时间，多个时间用逗号分隔
            - 星期用英文：Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
            - 时间用24小时制：08:00-09:40
            - 如果看不清楚某些信息，请用空字符串或默认值
            """;
    }

    /**
     * 调用智谱GLM-4V进行OCR识别
     */
    private String callGLMForOCR(String prompt, String imageUrl) {
        try {
            log.info("开始调用智谱GLM-4V模型进行OCR识别，图片URL: {}", imageUrl);
            
            ZhipuAiClient client = getZhipuClient();
            
            // 构建请求参数  
            ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
                    .model("glm-4.5v")
                    .messages(Arrays.asList(
                            ChatMessage.builder()
                                    .role(ChatMessageRole.USER.value())
                                    .content(Arrays.asList(
                                            MessageContent.builder()
                                                    .type("text")
                                                    .text(prompt)
                                                    .build(),
                                            MessageContent.builder()
                                                    .type("image_url")
                                                    .imageUrl(ImageUrl.builder()
                                                            .url(imageUrl)
                                                            .build())
                                                    .build()))
                                    .build()))
                    .temperature(0.1F)  // 修改为double类型
                    .maxTokens(3000)   // 足够的token数量
                    .build();
            
            // 调用API
            ChatCompletionResponse response = client.chat().createChatCompletion(request);
            
            if (response.isSuccess()) {
                if (response.getData() == null || response.getData().getChoices() == null || response.getData().getChoices().isEmpty()) {
                    log.error("智谱GLM-4V返回数据为空");
                    throw new RuntimeException("智谱GLM-4V返回数据为空");
                }
                
                Object content = response.getData().getChoices().get(0).getMessage().getContent();
                String result = content != null ? content.toString() : "";
                log.info("智谱GLM-4V识别完成，响应长度: {}", result.length());
                
                if (result.isEmpty()) {
                    log.error("智谱GLM-4V返回内容为空，可能是图片无法识别或URL无法访问");
                    // 尝试返回一个默认的测试响应
                    return createTestResponse();
                }
                
                return result;
            } else {
                log.error("智谱GLM-4V API调用失败: {}", response.getMsg());
                throw new RuntimeException("智谱GLM-4V API调用失败: " + response.getMsg());
            }
            
        } catch (Exception e) {
            log.error("调用智谱GLM-4V API失败: ", e);
            throw new RuntimeException("AI识别失败: " + e.getMessage());
        }
    }

    /**
     * 创建测试响应（当AI无法识别图片时的备用方案）
     */
    private String createTestResponse() {
        log.info("使用测试响应作为备用方案");
        return """
            {
                "courses": [
                    {
                        "courseName": "工程经济学",
                        "teacherName": "",
                        "credit": 2,
                        "courseType": 0,
                        "classroom": "东11B321",
                        "weekStart": 1,
                        "weekEnd": 20,
                        "classTime": "Monday:08:00-09:40,Wednesday:08:00-09:40",
                        "courseDescription": "测试数据 - AI无法识别图片时的备用方案"
                    },
                    {
                        "courseName": "软件构造",
                        "teacherName": "",
                        "credit": 2,
                        "courseType": 0,
                        "classroom": "东3110",
                        "weekStart": 1,
                        "weekEnd": 20,
                        "classTime": "Tuesday:08:00-09:40,Thursday:08:00-09:40",
                        "courseDescription": "测试数据 - AI无法识别图片时的备用方案"
                    }
                ]
            }
            """;
    }

    /**
     * 解析AI返回的课程信息
     */
    private List<Course> parseCoursesFromAIResponse(Integer userId, String aiResponse) {
        List<Course> courses = new ArrayList<>();
        
        try {
            // 提取JSON部分
            String jsonStr = extractJsonFromResponse(aiResponse);
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            JSONArray courseArray = jsonObject.getJSONArray("courses");
            
            if (courseArray != null) {
                for (int i = 0; i < courseArray.size(); i++) {
                    JSONObject courseJson = courseArray.getJSONObject(i);
                    Course course = new Course();
                    
                    course.setUserId(userId);
                    course.setCourseName(courseJson.getString("courseName"));
                    course.setTeacherName(courseJson.getString("teacherName"));
                    course.setCredit(courseJson.getIntValue("credit"));
                    course.setCourseType(courseJson.getIntValue("courseType"));
                    course.setClassroom(courseJson.getString("classroom"));
                    course.setWeekStart(courseJson.getIntValue("weekStart"));
                    course.setWeekEnd(courseJson.getIntValue("weekEnd"));
                    course.setClassTime(courseJson.getString("classTime"));
                    course.setCourseDescription(courseJson.getString("courseDescription"));
                    course.setExamType(0); // 默认考试
                    
                    courses.add(course);
                }
            }
            
        } catch (Exception e) {
            log.error("解析AI响应失败: ", e);
            // 如果JSON解析失败，尝试从文本中提取关键信息
            courses = parseCoursesFromText(userId, aiResponse);
        }
        
        return courses;
    }

    /**
     * 从响应中提取JSON字符串
     */
    private String extractJsonFromResponse(String response) {
        log.debug("原始响应内容: {}", response);
        
        // DeepSeek Reasoner可能在响应中包含推理过程，需要更智能地提取JSON
        
        // 方法1: 查找```json代码块
        String jsonBlockPattern = "```json\\s*([\\s\\S]*?)\\s*```";
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(jsonBlockPattern);
        java.util.regex.Matcher matcher = pattern.matcher(response);
        
        if (matcher.find()) {
            String jsonStr = matcher.group(1).trim();
            log.info("从代码块中提取到JSON: {}", jsonStr.substring(0, Math.min(100, jsonStr.length())) + "...");
            return jsonStr;
        }
        
        // 方法2: 查找完整的JSON对象
        int start = response.indexOf("{\"courses\"");
        if (start >= 0) {
            int braceCount = 0;
            int end = start;
            
            for (int i = start; i < response.length(); i++) {
                char c = response.charAt(i);
                if (c == '{') braceCount++;
                else if (c == '}') {
                    braceCount--;
                    if (braceCount == 0) {
                        end = i + 1;
                        break;
                    }
                }
            }
            
            if (end > start) {
                String jsonStr = response.substring(start, end);
                log.info("通过括号匹配提取到JSON: {}", jsonStr.substring(0, Math.min(100, jsonStr.length())) + "...");
                return jsonStr;
            }
        }
        
        // 方法3: 传统方法
        start = response.indexOf("{");
        int end = response.lastIndexOf("}") + 1;
        
        if (start >= 0 && end > start) {
            String jsonStr = response.substring(start, end);
            log.info("通过传统方法提取到JSON: {}", jsonStr.substring(0, Math.min(100, jsonStr.length())) + "...");
            return jsonStr;
        }
        
        log.error("无法从响应中提取JSON，响应内容: {}", response);
        throw new RuntimeException("无法从AI响应中提取JSON格式数据");
    }

    /**
     * 从文本中解析课程信息（备用方案）
     */
    private List<Course> parseCoursesFromText(Integer userId, String text) {
        List<Course> courses = new ArrayList<>();
        
        // 简单的文本解析逻辑，可以根据实际需要完善
        String[] lines = text.split("\n");
        Course currentCourse = null;
        
        for (String line : lines) {
            line = line.trim();
            if (line.isEmpty()) continue;
            
            // 检测是否是新课程开始
            if (line.contains("课程") || line.contains("Course")) {
                if (currentCourse != null) {
                    courses.add(currentCourse);
                }
                currentCourse = new Course();
                currentCourse.setUserId(userId);
                currentCourse.setCredit(2);
                currentCourse.setCourseType(0);
                currentCourse.setWeekStart(1);
                currentCourse.setWeekEnd(16);
                currentCourse.setExamType(0);
            }
            
            if (currentCourse != null) {
                // 提取课程名称
                if (line.contains("名称") || line.contains("课程")) {
                    currentCourse.setCourseName(extractValue(line));
                }
                // 提取教师姓名
                else if (line.contains("教师") || line.contains("老师")) {
                    currentCourse.setTeacherName(extractValue(line));
                }
                // 提取教室
                else if (line.contains("教室") || line.contains("地点")) {
                    currentCourse.setClassroom(extractValue(line));
                }
            }
        }
        
        if (currentCourse != null) {
            courses.add(currentCourse);
        }
        
        return courses;
    }

    /**
     * 从文本行中提取值
     */
    private String extractValue(String line) {
        String[] parts = line.split("[:：]");
        if (parts.length > 1) {
            return parts[1].trim();
        }
        return line.trim();
    }

    /**
     * 解析课程时间并添加到课程表中
     */
    private void parseAndAddCourseToSchedule(Course course, Map<String, List<Map<String, Object>>> weeklySchedule) {
        if (course.getClassTime() == null || course.getClassTime().isEmpty()) {
            return;
        }
        
        try {
            // 解析classTime格式：Monday:08:00-09:40,Wednesday:14:00-15:40
            String[] timeParts = course.getClassTime().split(",");
            
            for (String timePart : timeParts) {
                timePart = timePart.trim();
                
                // 使用更精确的方式解析时间，避免冒号分割的问题
                int firstColonIndex = timePart.indexOf(":");
                if (firstColonIndex > 0) {
                    String day = timePart.substring(0, firstColonIndex).trim();
                    String timeRange = timePart.substring(firstColonIndex + 1).trim(); // 08:00-09:40
                    
                    if (weeklySchedule.containsKey(day)) {
                        Map<String, Object> courseInfo = new HashMap<>();
                        courseInfo.put("time", timeRange);
                        courseInfo.put("courseName", course.getCourseName());
                        courseInfo.put("teacherName", course.getTeacherName());
                        courseInfo.put("classroom", course.getClassroom());
                        courseInfo.put("courseId", course.getId());
                        
                        weeklySchedule.get(day).add(courseInfo);
                    }
                }
            }
            
            // 对每天的课程按时间排序
            for (List<Map<String, Object>> dailyCourses : weeklySchedule.values()) {
                dailyCourses.sort((a, b) -> {
                    String timeA = (String) a.get("time");
                    String timeB = (String) b.get("time");
                    return timeA.compareTo(timeB);
                });
            }
            
        } catch (Exception e) {
            log.error("解析课程时间失败: {}", course.getClassTime(), e);
        }
    }

    @Override
    public CourseDetailVO getCourseDetail(Integer courseId) {
        try {
            Course course = courseMapper.selectById(courseId);
            if (course == null) {
                throw new RuntimeException("课程不存在");
            }
            
            return convertToDetailVO(course);
            
        } catch (Exception e) {
            log.error("获取课程详情失败: courseId={}", courseId, e);
            throw new RuntimeException("获取课程详情失败: " + e.getMessage());
        }
    }

    @Override
    public CourseDetailVO createCourse(CourseCreateDTO courseCreateDTO) {
        try {
            // 参数校验
            validateCourseCreateDTO(courseCreateDTO);
            
            Course course = new Course();
            BeanUtils.copyProperties(courseCreateDTO, course);
            
            course.setCreateTime(LocalDateTime.now());
            course.setUpdateTime(LocalDateTime.now());
            course.setIsDelete(0);
            
            // 设置默认值
            if (course.getCredit() == null) course.setCredit(2);
            if (course.getCourseType() == null) course.setCourseType(0);
            if (course.getExamType() == null) course.setExamType(0);
            if (course.getWeekStart() == null) course.setWeekStart(1);
            if (course.getWeekEnd() == null) course.setWeekEnd(20);
            
            // 检查时间冲突
            checkCourseTimeConflict(course.getUserId(), course.getClassTime(), 
                                  course.getWeekStart(), course.getWeekEnd(), null);
            
            int result = courseMapper.insert(course);
            if (result <= 0) {
                throw new RuntimeException("新增课程失败");
            }
            
            log.info("成功新增课程: courseId={}, courseName={}", course.getId(), course.getCourseName());
            return convertToDetailVO(course);
            
        } catch (Exception e) {
            log.error("新增课程失败: courseName={}", courseCreateDTO.getCourseName(), e);
            throw new RuntimeException("新增课程失败: " + e.getMessage());
        }
    }

    @Override
    public CourseDetailVO editCourse(CourseEditDTO courseEditDTO) {
        try {
            // 参数校验
            validateCourseEditDTO(courseEditDTO);
            
            // 检查课程是否存在
            Course existingCourse = courseMapper.selectById(courseEditDTO.getId());
            if (existingCourse == null) {
                throw new RuntimeException("课程不存在");
            }
            
            // 更新课程信息
            Course course = new Course();
            BeanUtils.copyProperties(courseEditDTO, course);
            course.setUpdateTime(LocalDateTime.now());
            
            // 设置默认值（如果为空）
            if (course.getWeekStart() == null) course.setWeekStart(existingCourse.getWeekStart());
            if (course.getWeekEnd() == null) course.setWeekEnd(existingCourse.getWeekEnd());
            
            // 检查时间冲突（排除当前课程）
            checkCourseTimeConflict(course.getUserId(), course.getClassTime(), 
                                  course.getWeekStart(), course.getWeekEnd(), course.getId());
            
            int result = courseMapper.updateById(course);
            if (result <= 0) {
                throw new RuntimeException("编辑课程失败");
            }
            
            log.info("成功编辑课程: courseId={}, courseName={}", course.getId(), course.getCourseName());
            
            // 返回更新后的课程详情
            Course updatedCourse = courseMapper.selectById(course.getId());
            return convertToDetailVO(updatedCourse);
            
        } catch (Exception e) {
            log.error("编辑课程失败: courseId={}", courseEditDTO.getId(), e);
            throw new RuntimeException("编辑课程失败: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteCourse(Integer courseId) {
        try {
            if (courseId == null) {
                throw new RuntimeException("课程ID不能为空");
            }
            
            // 检查课程是否存在
            Course existingCourse = courseMapper.selectById(courseId);
            if (existingCourse == null) {
                throw new RuntimeException("课程不存在");
            }
            
            // 逻辑删除
            Course course = new Course();
            course.setId(courseId);
            course.setIsDelete(1);
            course.setUpdateTime(LocalDateTime.now());
            
            int result = courseMapper.updateById(course);
            boolean success = result > 0;
            
            if (success) {
                log.info("成功删除课程: courseId={}", courseId);
            }
            
            return success;
            
        } catch (Exception e) {
            log.error("删除课程失败: courseId={}", courseId, e);
            throw new RuntimeException("删除课程失败: " + e.getMessage());
        }
    }

    @Override
    public List<CourseDetailVO> getUserCourses(Integer userId) {
        try {
            if (userId == null) {
                throw new RuntimeException("用户ID不能为空");
            }
            
            QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", userId)
                       .eq("isDelete", 0)
                       .orderByAsc("weekStart", "classTime");
            
            List<Course> courses = courseMapper.selectList(queryWrapper);
            
            List<CourseDetailVO> result = new ArrayList<>();
            for (Course course : courses) {
                result.add(convertToDetailVO(course));
            }
            
            log.info("获取用户课程列表成功: userId={}, count={}", userId, result.size());
            return result;
            
        } catch (Exception e) {
            log.error("获取用户课程列表失败: userId={}", userId, e);
            throw new RuntimeException("获取用户课程列表失败: " + e.getMessage());
        }
    }

    /**
     * 将Course实体转换为CourseDetailVO
     */
    private CourseDetailVO convertToDetailVO(Course course) {
        CourseDetailVO vo = new CourseDetailVO();
        BeanUtils.copyProperties(course, vo);
        
        // 添加类型描述
        vo.setCourseTypeDesc(getCourseTypeDesc(course.getCourseType()));
        vo.setExamTypeDesc(getExamTypeDesc(course.getExamType()));
        
        return vo;
    }

    /**
     * 获取课程类型描述
     */
    private String getCourseTypeDesc(Integer courseType) {
        if (courseType == null) return "";
        switch (courseType) {
            case 0: return "必修课";
            case 1: return "选修课";
            case 2: return "公共课";
            default: return "未知";
        }
    }

    /**
     * 获取考试类型描述
     */
    private String getExamTypeDesc(Integer examType) {
        if (examType == null) return "";
        switch (examType) {
            case 0: return "考试";
            case 1: return "考查";
            default: return "未知";
        }
    }

    /**
     * 检查课程时间冲突
     * @param userId 用户ID
     * @param classTime 课程时间段
     * @param weekStart 开始周次
     * @param weekEnd 结束周次
     * @param excludeCourseId 排除的课程ID（编辑时使用，新增时传null）
     */
    private void checkCourseTimeConflict(Integer userId, String classTime, 
                                       Integer weekStart, Integer weekEnd, Integer excludeCourseId) {
        // 如果没有设置时间段，则不需要检查冲突
        if (classTime == null || classTime.trim().isEmpty()) {
            return;
        }
        
        // 如果周次信息不完整，跳过检查
        if (weekStart == null || weekEnd == null) {
            return;
        }
        
        try {
            log.info("检查课程时间冲突: userId={}, classTime={}, weekStart={}, weekEnd={}, excludeCourseId={}", 
                    userId, classTime, weekStart, weekEnd, excludeCourseId);
            
            // 查询可能冲突的课程
            List<Course> conflictCourses = courseMapper.findConflictCourses(
                userId, classTime, weekStart, weekEnd, excludeCourseId);
            
            if (conflictCourses.isEmpty()) {
                log.info("未发现时间冲突");
                return;
            }
            
            // 解析当前课程的时间段
            List<TimeSlot> currentTimeSlots = parseTimeSlots(classTime);
            
            // 检查每个可能冲突的课程
            for (Course conflictCourse : conflictCourses) {
                if (hasTimeConflict(currentTimeSlots, conflictCourse, weekStart, weekEnd)) {
                    String conflictInfo = String.format("与课程【%s】时间冲突，冲突时间段：%s，冲突周次：%d-%d周", 
                        conflictCourse.getCourseName(), 
                        conflictCourse.getClassTime(),
                        Math.max(weekStart, conflictCourse.getWeekStart()),
                        Math.min(weekEnd, conflictCourse.getWeekEnd()));
                    
                    log.warn("发现课程时间冲突: {}", conflictInfo);
                    throw new RuntimeException("课程时间冲突：" + conflictInfo);
                }
            }
            
            log.info("时间冲突检查通过");
            
        } catch (RuntimeException e) {
            throw e; // 重新抛出业务异常
        } catch (Exception e) {
            log.error("检查课程时间冲突失败", e);
            throw new RuntimeException("检查课程时间冲突失败: " + e.getMessage());
        }
    }
    
    /**
     * 解析时间段字符串为时间段对象列表
     * @param classTime 课程时间段，格式如：Monday:08:00-09:40,Wednesday:14:00-15:40
     * @return 时间段列表
     */
    private List<TimeSlot> parseTimeSlots(String classTime) {
        List<TimeSlot> timeSlots = new ArrayList<>();
        
        if (classTime == null || classTime.trim().isEmpty()) {
            return timeSlots;
        }
        
        String[] timeParts = classTime.split(",");
        for (String timePart : timeParts) {
            timePart = timePart.trim();
            int colonIndex = timePart.indexOf(":");
            if (colonIndex > 0) {
                String dayOfWeek = timePart.substring(0, colonIndex).trim();
                String timeRange = timePart.substring(colonIndex + 1).trim();
                
                TimeSlot slot = new TimeSlot();
                slot.setDayOfWeek(dayOfWeek);
                slot.setTimeRange(timeRange);
                timeSlots.add(slot);
            }
        }
        
        return timeSlots;
    }
    
    /**
     * 检查是否有时间冲突
     * @param currentTimeSlots 当前课程的时间段
     * @param conflictCourse 可能冲突的课程
     * @param currentWeekStart 当前课程开始周次
     * @param currentWeekEnd 当前课程结束周次
     * @return 是否冲突
     */
    private boolean hasTimeConflict(List<TimeSlot> currentTimeSlots, Course conflictCourse, 
                                  Integer currentWeekStart, Integer currentWeekEnd) {
        // 检查周次是否有重叠
        boolean weekOverlap = !(conflictCourse.getWeekEnd() < currentWeekStart || 
                               conflictCourse.getWeekStart() > currentWeekEnd);
        
        if (!weekOverlap) {
            return false; // 周次不重叠，不冲突
        }
        
        // 解析冲突课程的时间段
        List<TimeSlot> conflictTimeSlots = parseTimeSlots(conflictCourse.getClassTime());
        
        // 检查时间段是否冲突
        for (TimeSlot currentSlot : currentTimeSlots) {
            for (TimeSlot conflictSlot : conflictTimeSlots) {
                if (isTimeSlotConflict(currentSlot, conflictSlot)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * 检查两个时间段是否冲突
     * @param slot1 时间段1
     * @param slot2 时间段2
     * @return 是否冲突
     */
    private boolean isTimeSlotConflict(TimeSlot slot1, TimeSlot slot2) {
        // 如果不是同一天，不冲突
        if (!slot1.getDayOfWeek().equals(slot2.getDayOfWeek())) {
            return false;
        }
        
        // 解析时间范围
        String[] time1Parts = slot1.getTimeRange().split("-");
        String[] time2Parts = slot2.getTimeRange().split("-");
        
        if (time1Parts.length != 2 || time2Parts.length != 2) {
            return false; // 时间格式不正确，认为不冲突
        }
        
        try {
            // 转换为分钟数进行比较
            int start1 = timeToMinutes(time1Parts[0].trim());
            int end1 = timeToMinutes(time1Parts[1].trim());
            int start2 = timeToMinutes(time2Parts[0].trim());
            int end2 = timeToMinutes(time2Parts[1].trim());
            
            // 检查时间段是否重叠
            return !(end1 <= start2 || end2 <= start1);
            
        } catch (Exception e) {
            log.warn("解析时间段失败: slot1={}, slot2={}", slot1.getTimeRange(), slot2.getTimeRange(), e);
            return false; // 解析失败，认为不冲突
        }
    }
    
    /**
     * 将时间字符串转换为分钟数
     * @param timeStr 时间字符串，如"08:00"
     * @return 分钟数
     */
    private int timeToMinutes(String timeStr) {
        String[] parts = timeStr.split(":");
        if (parts.length != 2) {
            throw new IllegalArgumentException("时间格式不正确: " + timeStr);
        }
        
        int hours = Integer.parseInt(parts[0]);
        int minutes = Integer.parseInt(parts[1]);
        
        return hours * 60 + minutes;
    }
    
    /**
     * 时间段内部类
     */
    private static class TimeSlot {
        private String dayOfWeek; // 星期几
        private String timeRange; // 时间范围，如"08:00-09:40"
        
        public String getDayOfWeek() {
            return dayOfWeek;
        }
        
        public void setDayOfWeek(String dayOfWeek) {
            this.dayOfWeek = dayOfWeek;
        }
        
        public String getTimeRange() {
            return timeRange;
        }
        
        public void setTimeRange(String timeRange) {
            this.timeRange = timeRange;
        }
    }

    /**
     * 校验新增课程DTO
     */
    private void validateCourseCreateDTO(CourseCreateDTO courseCreateDTO) {
        if (courseCreateDTO.getUserId() == null) {
            throw new RuntimeException("用户ID不能为空");
        }
        if (courseCreateDTO.getCourseName() == null || courseCreateDTO.getCourseName().trim().isEmpty()) {
            throw new RuntimeException("课程名称不能为空");
        }
        if (courseCreateDTO.getWeekStart() != null && courseCreateDTO.getWeekEnd() != null) {
            if (courseCreateDTO.getWeekStart() > courseCreateDTO.getWeekEnd()) {
                throw new RuntimeException("开始周次不能大于结束周次");
            }
        }
    }

    /**
     * 校验课程编辑DTO
     */
    private void validateCourseEditDTO(CourseEditDTO courseEditDTO) {
        if (courseEditDTO.getId() == null) {
            throw new RuntimeException("课程ID不能为空");
        }
        if (courseEditDTO.getUserId() == null) {
            throw new RuntimeException("用户ID不能为空");
        }
        if (courseEditDTO.getCourseName() == null || courseEditDTO.getCourseName().trim().isEmpty()) {
            throw new RuntimeException("课程名称不能为空");
        }
        if (courseEditDTO.getWeekStart() != null && courseEditDTO.getWeekEnd() != null) {
            if (courseEditDTO.getWeekStart() > courseEditDTO.getWeekEnd()) {
                throw new RuntimeException("开始周次不能大于结束周次");
            }
        }
    }
} 